package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

@Component
public class SeckillReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsService seckillGoodsService;



    /**
     * 将秒杀商品导入redis中
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}))
    public void getGoods(Channel channel, Message message) {

        try {
//        查寻当天的商品
            QueryWrapper<SeckillGoods> wrapper = new QueryWrapper<>();
            wrapper.eq("status", 1);
            //查询当前日期
            wrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
            wrapper.gt("stock_count", 0);
//            查询出当天秒杀商品数据
            List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectList(wrapper);

            if (CollectionUtils.isEmpty(seckillGoods)) {
                return;
            }

            for (SeckillGoods seckillGood : seckillGoods) {
                //            redis中有无数据
                Boolean flag = redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).hasKey(seckillGood.getSkuId().toString());
                if (flag) {
                    continue;//结束当前循环，进行下一次循环
                }
                //            添加到redis
                redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).put(seckillGood.getSkuId().toString(), seckillGood);

                //            获取商品库存数量
                for (Integer i = 0; i < seckillGood.getStockCount(); i++) {

                    String stockKey = RedisConst.SECKILL_STOCK_PREFIX + seckillGood.getSkuId();

                    //                          防止超卖，使用redis队列
                    //                redisTemplate.opsForList().leftPush(stockKey,seckillGood.getSkuId().toString());
                    //                防止超卖，使用redis队列
                    redisTemplate.boundListOps(stockKey).leftPush(seckillGood.getSkuId().toString());

//                    使用redis发送消息实现数据同步
                    redisTemplate.convertAndSend("seckillpush", seckillGood.getSkuId() + ":1");
                }
            }
            //    手动确认消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        }
    }

    /**
     * 秒杀用户加入队列
     *
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER, type = ExchangeTypes.DIRECT, durable = "true"),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void seckill(UserRecode userRecode, Message message, Channel channel) throws IOException {

        if (null != userRecode) {
            //预下单
            seckillGoodsService.seckillOrder(userRecode.getSkuId(), userRecode.getUserId());

            //确认收到消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    /**
     * 秒杀结束清空缓存
     *
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK, type = ExchangeTypes.DIRECT, durable = "true"),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearRedis(Message message, Channel channel) throws IOException {

//            查询秒杀过期商品信息
        QueryWrapper<SeckillGoods> wrapper = new QueryWrapper<>();
        wrapper.eq("status", 1);
        wrapper.le("end_time", new Date());

        List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectList(wrapper);

        for (SeckillGoods seckillGood : seckillGoods) {
//            删除秒杀的商品信息
            redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).delete(seckillGood.getSkuId());
        }

//        删除预下单商品信息
        redisTemplate.delete(RedisConst.SECKILL_ORDERS);
//        删除商品下单信息
        redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);
//        删除库存信息
        redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX);

//        更改数据库
        SeckillGoods goods = new SeckillGoods();
        goods.setStatus("2");
        seckillGoodsMapper.update(goods, wrapper);
//        确认信息发送
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}